<script setup lang="ts" name="VerifyPoints" generic="VerifyPoints">
/**
 * VerifyPoints
 * @description 点选
 */
import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from "vue"
import { resetSize } from "./../utils/util"
import { aesEncrypt } from "./../utils/ase"
import { checkCaptcha, getCaptcha } from "../../../../api/login"
import { useI18n } from "../utils/i18n"

const props = defineProps({
  // 弹出式pop，固定fixed
  mode: {
    type: String,
    default: "fixed",
  },
  captchaType: {
    type: String,
  },
  // 间隔
  vSpace: {
    type: Number,
    default: 5,
  },
  imgSize: {
    type: Object,
    default() {
      return {
        width: "310px",
        height: "155px",
      }
    },
  },
  barSize: {
    type: Object,
    default() {
      return {
        width: "310px",
        height: "40px",
      }
    },
  },
})

const { t } = useI18n()
const { mode, captchaType } = toRefs(props)
const instance = getCurrentInstance()
const proxy = instance?.proxy
const secretKey = ref("") // 后端返回的ase加密秘钥
const checkNum = ref(3) // 默认需要点击的字数
const fontPos = reactive<any[]>([]) // 选中的坐标信息
const checkPosArr = reactive<any[]>([]) // 用户点击的坐标
const num = ref(1) // 点击的记数
const pointBackImgBase = ref("") // 后端获取到的背景图片
const poinTextList = reactive<string[]>([]) // 后端返回的点击字体顺序
const backToken = ref("") // 后端返回的token值
const setSize = reactive({
  imgHeight: 0,
  imgWidth: 0,
  barHeight: 0,
  barWidth: 0,
})
const tempPoints = reactive<any[]>([])
const text = ref("")
const barAreaColor = ref<string>("#000")
const barAreaBorderColor = ref<string>("#ddd")
const showRefresh = ref(true)
const bindingClick = ref(true)

function init() {
  // 加载页面
  fontPos.splice(0, fontPos.length)
  checkPosArr.splice(0, checkPosArr.length)
  num.value = 1
  getPictrue()
  nextTick(() => {
    const { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy)
    setSize.imgHeight = imgHeight
    setSize.imgWidth = imgWidth
    setSize.barHeight = barHeight
    setSize.barWidth = barWidth
    proxy?.$parent?.$emit("ready", proxy)
  })
}

onMounted(() => {
  // 禁止拖拽
  init()
  if (proxy?.$el) {
    proxy.$el.onselectstart = function () {
      return false
    }
  }
})

const canvas = ref(null)

// 获取坐标
const getMousePos = function (_obj: any, e: any) {
  const x = e.offsetX
  const y = e.offsetY
  return { x, y }
}

// 创建坐标点
const createPoint = function (pos: { x: number; y: number }) {
  tempPoints.push(Object.assign({}, pos))
  return num.value + 1
}

// 坐标转换函数
const pointTransfrom = function (pointArr: any[], imgSize: any) {
  const newPointArr = pointArr.map((p) => {
    const x = Math.round((310 * p.x) / Number.parseInt(imgSize.imgWidth))
    const y = Math.round((155 * p.y) / Number.parseInt(imgSize.imgHeight))
    return { x, y }
  })
  return newPointArr
}

const refresh = async function () {
  tempPoints.splice(0, tempPoints.length)
  barAreaColor.value = "#000"
  barAreaBorderColor.value = "#ddd"
  bindingClick.value = true
  fontPos.splice(0, fontPos.length)
  checkPosArr.splice(0, checkPosArr.length)
  num.value = 1
  await getPictrue()
  showRefresh.value = true
}

function canvasClick(e: any) {
  checkPosArr.push(getMousePos(canvas.value, e))
  if (num.value === checkNum.value) {
    num.value = createPoint(getMousePos(canvas.value, e))
    // 按比例转换坐标值
    const arr = pointTransfrom(checkPosArr, setSize)
    checkPosArr.length = 0
    checkPosArr.push(...arr)
    // 等创建坐标执行完
    setTimeout(() => {
      // 发送后端请求
      const captchaVerification = secretKey.value ? aesEncrypt(`${backToken.value}---${JSON.stringify(checkPosArr)}`, secretKey.value) : `${backToken.value}---${JSON.stringify(checkPosArr)}`
      const data = {
        captchaType: captchaType?.value,
        pointJson: secretKey.value ? aesEncrypt(JSON.stringify(checkPosArr), secretKey.value) : JSON.stringify(checkPosArr),
        token: backToken.value,
      }
      checkCaptcha(data).then((response) => {
        const res = response.data
        if (res.repCode === "0000") {
          barAreaColor.value = "#4cae4c"
          barAreaBorderColor.value = "#5cb85c"
          text.value = t("component.captcha.success")
          bindingClick.value = false
          if (mode.value === "pop" && proxy?.$parent) {
            setTimeout(() => {
              ;(proxy.$parent as any).clickShow = false
              refresh()
            }, 1500)
          }
          proxy?.$parent?.$emit("success", { captchaVerification })
        } else {
          proxy?.$parent?.$emit("error", proxy)
          barAreaColor.value = "#d9534f"
          barAreaBorderColor.value = "#d9534f"
          text.value = t("component.captcha.fail")
          setTimeout(() => {
            refresh()
          }, 700)
        }
      })
    }, 400)
  }
  if (num.value < checkNum.value) num.value = createPoint(getMousePos(canvas.value, e))
}

// 请求背景图片和验证图片
async function getPictrue() {
  const data = {
    captchaType: captchaType?.value,
  }
  const res = await getCaptcha(data)
  if (res.data.repCode === "0000") {
    pointBackImgBase.value = res.data.repData.originalImageBase64
    backToken.value = res.data.repData.token
    secretKey.value = res.data.repData.secretKey
    poinTextList.splice(0, poinTextList.length, ...res.data.repData.wordList)
    text.value = `${t("component.captcha.point")}【${poinTextList.join(",")}】`
  } else {
    text.value = res.data.repMsg
  }
}

defineExpose({
  refresh,
})
</script>

<template>
  <div style="position: relative">
    <div class="verify-img-out">
      <div
        class="verify-img-panel"
        :style="{
          width: setSize.imgWidth,
          height: setSize.imgHeight,
          'background-size': `${setSize.imgWidth} ${setSize.imgHeight}`,
          'margin-bottom': `${vSpace}px`,
        }"
      >
        <div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
          <i class="iconfont icon-refresh" />
        </div>
        <img ref="canvas" :src="`data:image/png;base64,${pointBackImgBase}`" alt="" style="display: block; width: 100%; height: 100%" @click="bindingClick ? canvasClick($event) : undefined" />

        <div
          v-for="(tempPoint, index) in tempPoints"
          :key="index"
          class="point-area"
          :style="{
            'background-color': '#1abd6c',
            color: '#fff',
            'z-index': 9999,
            width: '20px',
            height: '20px',
            'text-align': 'center',
            'line-height': '20px',
            'border-radius': '50%',
            position: 'absolute',
            top: `${Number(tempPoint.y - 10).toString()}px`,
            left: `${Number(tempPoint.x - 10).toString()}px`,
          }"
        >
          {{ index + 1 }}
        </div>
      </div>
    </div>
    <div
      class="verify-bar-area"
      :style="{
        width: setSize.imgWidth,
        color: barAreaColor,
        'border-color': barAreaBorderColor,
        'line-height': barSize.height,
      }"
    >
      <span class="verify-msg">{{ text }}</span>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent as _defineComponent } from "vue"
export default _defineComponent({
  name: "VerifyPoints",
})
</script>
